#include "QuadNode.h"
#include "Line.h"

#define NUM_LINES_NODE 15
#define MAX_DEPTH 10
#define MIN_GRID_LENGTH ((BOX_XMAX - BOX_XMIN) / pow(2, MAX_DEPTH))
using namespace std;

QuadNode::QuadNode() {
    vector<Line*> no_lines;
    QuadNode(0.0, 0.0, 0.0, 0.0, no_lines);
}

QuadNode::QuadNode(double x_0, double y_0, double x_f, double y_f, vector<Line*> lines){
    this->x_0 = x_0;
    this->y_0 = y_0;
    this->x_f = x_f;
    this->y_f = y_f;
    top_left = NULL;
    top_right = NULL;
    bottom_left = NULL;
    bottom_right = NULL;

    myLines.clear();
    if (lines.size() != 0){
        lineClassify(lines);
    }
}

//getter functions for child nodes
QuadNode* QuadNode::getTopLeft(){
    return top_left;
}
QuadNode* QuadNode::getTopRight(){
    return top_right;
}
QuadNode* QuadNode::getBottomLeft(){
    return bottom_left;
}
QuadNode* QuadNode::getBottomRight(){
    return bottom_right;
}

QuadNode* QuadNode::allocateNode(double x_0, double y_0,double x_f,double y_f, vector<Line*> line_vec){
    QuadNode* thisNode= new QuadNode(x_0, y_0, x_f, y_f, line_vec);
    return thisNode;
}
//getter function for this nodes lines
vector<Line*> QuadNode::getLines(){
    return myLines;
}
//deletion
QuadNode::~QuadNode(){
    if (top_left){
        delete (top_left);
    }
    if (top_right){
        delete (top_right);
    }
    if (bottom_left){
        delete (bottom_left);
    }
    if (bottom_right){
        delete (bottom_right);
    }
}
int QuadNode::getCount() {
  int sum = myLines.size();
   if (top_left){
        sum += top_left->getCount();
    }
    if (top_right){
        sum += top_right->getCount();
    }
    if (bottom_left){
        sum += bottom_left->getCount();
    }
    if (bottom_right){
        sum += bottom_right->getCount();
    }
    return sum;

}
//classifies a vector of lines into its 4 child nodes
void QuadNode::lineClassify(vector<Line*> lines){
    vector<Line*> top_left_vec;
    vector<Line*> bottom_left_vec;
    vector<Line*> top_right_vec;
    vector<Line*> bottom_right_vec;
    vector<Line*> spanLines;
    //box is too small
    if((y_f - y_0)/2.0 == 0.0){
        cout<<"too small"<<endl;
        return;
    }
    
//the mid point of the bounds of this node
    double x_m =  (x_f + x_0)/2.0;
    double y_m =  (y_f + y_0)/2.0;
    

// if there are few nodes, do not bother splitting
    if (lines.size() < NUM_LINES_NODE){
      myLines.insert(myLines.end(), lines.begin(), lines.end());
      return;
    }
    if (x_f - x_0 < MIN_GRID_LENGTH)
    {
      if(lines.size() > 0)
      {
	myLines.insert(myLines.end(), lines.begin(), lines.end());
      }
      return;
    }
    vector<Line*>::iterator it1;
    for (it1 = lines.begin(); it1 != lines.end(); ++it1) {       
        Line* thisLine = *it1;
        double x1cor = thisLine->p1.x;
        double y1cor = thisLine->p1.y;
        
        double x2cor = thisLine->p2.x;
        double y2cor = thisLine->p2.y;

        //both vertices on the left
        if ( (x1cor < x_m) && (x2cor < x_m)){
            //both vertices on the bottom half
            if ((y1cor < y_m) && (y2cor < y_m)){
                bottom_left_vec.push_back(thisLine);
            }
            //both vertices on the top half
            else if ((y1cor > y_m) && (y2cor > y_m)){
                top_left_vec.push_back(thisLine);
            }
            else{
                spanLines.push_back(thisLine);
            }
        }
        //both vertices on right half
        else if( (x1cor > x_m) && (x2cor > x_m)){
            //both vertices on the bottom half
            if ((y1cor < y_m) && (y2cor < y_m)){
                bottom_right_vec.push_back(thisLine);
            }
            //both vertices on the top half
            else if ((y1cor > y_m) && (y2cor > y_m)){
                top_right_vec.push_back(thisLine);
            }
            else{
                spanLines.push_back(thisLine);
            }
            
        }
        //add to the lsit representing lines that span more than one quadrant
        else{
            spanLines.push_back(thisLine);
        }

    }
    //set the children
//    cout << top_left_vec.size() << " " <<top_right_vec.size() << " "<<bottom_left_vec.size() << " " <<bottom_right_vec.size() << " " << spanLines.size() << endl;
        myLines.insert(myLines.end(), spanLines.begin(),spanLines.end() );
         
        top_left    =  new QuadNode(x_0,y_0,x_m,y_m,top_left_vec);
        
        top_right   =  new QuadNode(x_m,y_0,x_f,y_m,top_right_vec);
        
        bottom_left =  new QuadNode(x_0,y_m,x_m,y_f,bottom_left_vec);
        
        bottom_right=  new QuadNode(x_m,y_m,x_f,y_f,bottom_right_vec);
        //???
        
}
